// messages.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing messages
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"



//@ SEC 3
//@ CHA Message Master Retrieve
//@ COD MessageMasterRetrieve
//@ TAB Message_Master Read
//@ GEN Use MessageMasterRetrieve to retrieve message_master record
bool MessageMasterRetrieve( XCBuffer* input, XCTransactionVars* vars ) {
	return DatabaseRetrievePrimary( input, vars );
};


void MessageMasterAdd( XCBuffer* input, bool pro_mode, XCTransactionVars* vars ) {
	input->GetField( FLD_SYSTEM_OBJECT )->SetBool( pro_mode );
	DatabaseAddPrimary( input, vars );
};

void MessageMasterDel( XCBuffer* input, XCTransactionVars* vars ) {
	//@ Delete this record
	DatabaseDelPrimary( input, vars );
};

void MessageMasterChange( XCBuffer* input, XCBuffer* original, XCTransactionVars* vars ) {
	if (input->MarkChanges( original ))
		DatabaseChgPrimary( input, original, vars );
};

//@ SEC 3
//@ CHA Message Defn Retrieve
//@ COD MessageDefnRetrieve
//@ TAB Message_Defn Read
//@ GEN Use MessageDefnRetrieve to retrieve message_defn record
bool MessageDefnRetrieve( XCBuffer* input, XCTransactionVars* vars ) {
	return DatabaseRetrievePrimary( input, vars );
};




//@ SEC 3
//@ CHA Message Defn Verify
//@ COD MessageDefnVerify
//@ TAB Message_Defn Read
//@ GEN Use MessageDefnRetrieve to retrieve message_defn record
void MessageDefnVerify( XCBuffer* input, XCBuffer* master, verify_type verify_mode, XCTransactionVars* vars, bool pro_mode, XCBuffer* original, bool* has_master ) {
	TRANS_INFUNC( MessageDefnVerify );

	//@ Check for blank message number
	XCField* msg_nbr = vars->buffer->GetField( FLD_MSG_NBR );
	if (msg_nbr->IsBlank())
		vars->Errors->Add( ERR_IS_BLANK, SEV_CRITICAL, FLD_MSG_NBR, 1, msg_nbr );

	//@ Determine if this message number has a master record
	if (has_master)
		*has_master = MessageMasterRetrieve( master, vars );
	else
		MessageMasterRetrieve( master, vars );

	//@ If verifying an add transaction:
	if (verify_mode == VERIFY_ADD) {
		//@ GRS 

		//@ Check for a valid user message name (only if non-blank)
		//@ ERR C (INV_FIELD_NAME) Invalid field name
		XCField* temp = vars->buffer->GetField( FLD_MSG_NAME );
		if (temp && !temp->IsBlank()) {
			//@ SUB ValidateName to check for a valid name
			ValidateName( FLD_MSG_NAME, vars->buffer, ERR_MESSAGE, vars );
		};

		//@ SUB MessageDefnRetrieve to ensure message number doesn't already exist
		//@ ERR E (ERR_ALREADY_EXISTS)
		if (MessageDefnRetrieve( input, vars ))
			vars->Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_MSG_NBR, 1, 20013 );
		//@ GRE
	} else {
		//@ Otherwise:
		//@ GRS
		//@ SUB MessageDefnRetrieve to ensure message already exists
		//@ ERR E (ERR_INV_DATASTRUCT)
		if (!MessageDefnRetrieve( original ? original : input, vars ))
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_MSG_NBR, 1, 20013 );
		//@ GRE
	};

	// Check system level vs pro level...
	if (verify_mode == VERIFY_DELETE) {
		if (!pro_mode && master->GetField( FLD_SYSTEM_OBJECT )->GetBool())
			vars->Errors->Add( ERR_CANNOT_DELETE_CRITICAL );
	};

	// Check for duplicate message name...
	if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_CHANGE) {
		XCField* name = input->GetField( FLD_MSG_NAME );
		if (original)
			input->MarkChanges( original );

		if (verify_mode == VERIFY_CHANGE && !name->IsChanged())
			name = NULL;

		if (name && !name->IsBlank()) {
			XCBuffer* tempbuf = NULL;
			XCDBStatement* stmt = NULL;
			XCField* cloned = NULL;

			try {
				tempbuf = vars->myapp->CreateBuffer( FMT_MSG_DEFN, true );
				XCField* list[5];
				XCCompare comp[5];

				cloned = input->GetField( FLD_APPL_NBR )->Clone();
				cloned->Clear();

				list[0] = input->GetField( FLD_MSG_NBR );
				list[1] = input->GetField( FLD_MSG_NAME );
				list[2] = input->GetField( FLD_APPL_NBR );
				list[3] = cloned;
				list[4] = NULL;

				comp[0].comparison = cmp_notequals;
				comp[2].preparen++;
				comp[3].logical = logic_or;
				comp[3].postparen++;

				vars->query->MakeSELECT( tempbuf );
				vars->query->AddWHERE( list, comp );

				stmt = vars->dbtxn->ExecuteSQL( vars->query );
				if (!stmt->Eof())
					vars->Errors->Add( ERR_INV_MESSAGE_NAME, SEV_CRITICAL );
			} catch( ... ) {
				vars->myapp->CleanupObjects( 3, &stmt, &tempbuf, &cloned );
				throw;
			};
			vars->myapp->CleanupObjects( 3, &stmt, &tempbuf, &cloned );
		};
	};

	OUTFUNC();
};




//@ SEC 3
//@ CHA Message Defn Add
//@ COD MessageDefnAdd
//@ TAB Message_Defn Read
//@ GEN Use MessageDefnRetrieve to retrieve message_defn record
void MessageDefnAdd( XCBuffer* buf, XCTransactionVars* vars ) {
	TRANS_INFUNC( MessageDefnAdd );

	XCSQLGen* query = vars->query;

/*
	XCDBStatement* stmt = NULL;
	XCBuffer* temp = NULL;
	long last_number = 0;

	//@ Determine the next available message field number
	temp = App->CreateBuffer( FMT_MSG_DEFN );
	try {
		XCOrder ord;
		XCCompare comp;
		bool found = false;

		query->MakeSELECT( temp );
		query->AddWHERE( buf->GetField( FLD_APPL_NBR ), &comp );
		query->AddORDERBY( FLD_MSG_NBR, &ord );
		stmt = vars->dbtxn->ExecuteSQL( query );
		while ( !found && !stmt->Eof() )
		{
			long value = temp->GetField( FLD_MSG_NBR )->GetLong( true );
			if ( value != last_number + 1 )
			{
				// we found a blank space
				found = true;
				last_number++;
			}
			else
			{
				last_number = value;
				stmt->MoveNext();
			};
		};

		// Cleanup now
		App->CleanupObjects( 2, &temp, &stmt );

		if (!found)
			last_number++;
		buf->GetField( FLD_MSG_NBR )->SetLong( last_number );

	} catch( ... ) {
		App->CleanupObjects( 2, &temp, &stmt );
		throw;
	};
*/

	//@ Add the message defn record
	DatabaseAddPrimary( buf, vars );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Message Defn Delete
//@ COD MessageDefnDelete
//@ TAB Message_Defn Read
//@ GEN Use MessageDefnRetrieve to retrieve message_defn record
void MessageDefnDelete( XCBuffer* input, XCTransactionVars* vars ) {
	TRANS_INFUNC( MessageDefnDelete );

	//@ Determine if we should remove the master record
	XCBuffer* master = NULL;
	XCBuffer* count = vars->query->MakeCOUNT( input, input->GetField( FLD_MSG_NBR ), false );
	try {
		vars->query->AddWHERE( 2, input->GetField( FLD_APPL_NBR ), input->GetField( FLD_MSG_NBR ) );
		vars->dbtxn->ExecuteSQL( vars->query, SQL_NO_RESULT );
		int result = count->GetFieldByIndex(0)->GetLong( true );
		if (result == 1) {
			master = vars->myapp->CreateBuffer( FMT_MSG_MASTER, false );
			master->MoveCorresponding( input, NULL );
			MessageMasterDel( master, vars );
		};

	} catch( ... ) {
		if (master)
			master->Release();
		count->Release();
		throw;
	};
	if (master)
		master->Release();
	count->Release();

	//@ Delete MSG_DEFN record
	DatabaseDelPrimary( input, vars );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Message Defn Change
//@ COD MessageDefnChange
//@ TAB Message_Defn Read
//@ GEN Use MessageDefnRetrieve to retrieve message_defn record
void MessageDefnChange( XCBuffer* input, XCBuffer* compare, XCTransactionVars* vars ) {
	TRANS_INFUNC( MessageDefnChange );

	//@ Issue update statement
	if (input->MarkChanges( compare ))
		DatabaseChgPrimary( input, compare, vars );

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Message Defn Delete All
//@ COD MessageDefnDeleteAll
//@ TAB MSG_DEFN Write
//@ GEN Use MessageDefnDeleteAll to remove fields
void MessageDefnDeleteAll( XCBuffer* input, XCTransactionVars* vars ) {
	XCSQLGen* query = vars->query;

	TRANS_INFUNC( MessageDefnDeleteAll );

	XCBuffer* fields = App->CreateBuffer( FMT_MSG_DEFN, false );
	try {
		fields->MoveField( input, FLD_APPL_NBR );

		//@ Delete FIELD_DESCRIPTOR records
		query->MakeDELETE( fields );
		query->AddWHERE( 1, fields->GetField( FLD_APPL_NBR ) );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
	} catch( ... ) {
		fields->Release();
		throw;
	};
	fields->Release();

	TRANS_OUTFUNC();
};




//////////////////////////////////////////////
//
// Internal functions
//
//////////////////////////////////////////////
void DelMessageInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* master = NULL;
	XCDBStatement* stmt = NULL;

	try {
		XCSQLGen* query = vars->query;

		//@ Create transaction buffer
		TransBuf = vars->myapp->CreateBuffer( FMT_MSG_DEFN, false );
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		TransBuf->Validate();
		TransBuf->DebugDump();

		master = vars->myapp->CreateBuffer( FMT_MSG_MASTER, false );
		master->MoveCorresponding( vars->buffer, vars->Errors );

		//@ SUB MessageDefnVerify to verify
		MessageDefnVerify( TransBuf, master, VERIFY_DELETE, vars, pro_mode );

		//@ Delete the message record
		MessageDefnDelete( TransBuf, vars );
	} catch( ... ) {
		vars->myapp->CleanupObjects( 3, &TransBuf, &stmt, &master );
		throw;
	};
	vars->myapp->CleanupObjects( 3, &TransBuf, &stmt, &master );
};

void AddMessageInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* master = NULL;

	try {
		//@ Create MSG_DEFN buffer
		TransBuf = vars->myapp->CreateBuffer( FMT_MSG_DEFN, false );
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		TransBuf->Validate();

		//@ Create a MSG_MASTER buffer
		master = vars->myapp->CreateBuffer( FMT_MSG_MASTER, false );
		master->MoveCorresponding( vars->buffer, vars->Errors );

		bool has_master = false;

		TransBuf->DebugDump();

		//@ SUB MessageDefnVerify Verify record
		MessageDefnVerify( TransBuf, master, VERIFY_ADD, vars, pro_mode, NULL, &has_master );

		vars->Errors->Check();

		//@ SUB MessageDefnAdd Add record
		MessageDefnAdd( TransBuf, vars );

		//@ Determine if a master record needs to be created
		if (!has_master) {
			//@ SUB MessageMasterAdd to add the new record
			MessageMasterAdd( master, pro_mode, vars );
		};

		//@ Move corresponding values from the transaction buffer to the output buffer
		vars->buffer->MoveCorresponding( TransBuf, vars->Errors );
	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &TransBuf, &master );
		throw;
	};
	vars->myapp->CleanupObjects( 2, &TransBuf, &master );
};
